package com.foreveross.proxyip.core.redis;

import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * redis锁
 * @author lyq
 *
 */
public class RedisLock {
	
	private static final Logger logger = LoggerFactory.getLogger(RedisLock.class);

	/** 加锁标志 */
	public static final String LOCKED = "TRUE";
	/** 毫秒与毫微秒的换算单位 1毫秒 = 1000000毫微秒 */
	public static final long MILLI_NANO_CONVERSION = 1000 * 1000L;
	/** 默认超时时间（毫秒） */
	public static final long DEFAULT_TIME_OUT = 1000;
	public static final Random RANDOM = new Random();
	/** 锁的超时时间（秒），过期删除 */
	private int expire = 10 * 60;
	private String key;  
	
	RedisManager redis = RedisManager.getInstance();
	
	
	
	/**
	 * This creates a RedisLock
	 * @param key key
	 * @param shardedJedisPool 数据源
	 */
	public RedisLock(String key) {
		this.key = key + "_lock";
		
	}
	
	public RedisLock(String key, int expire) {
		this.key = key + "_lock";
		this.expire = expire;
	}

	/**
	 * 加锁
	 * 应该以：
	 * lock();
	 * try {
	 * 		doSomething();
	 * } finally {
	 * 		unlock()；
	 * }
	 * 的方式调用 
	 * @param timeout 超时时间
	 * @return 成功或失败标志
	 */
	public boolean lock(long timeout) {

		long nano = System.nanoTime();
		timeout *= MILLI_NANO_CONVERSION;
		try {
			while ((System.nanoTime() - nano) < timeout) {
				if (redis.setnx(key, LOCKED, expire) == 1) {
					return true;
				}
				// 短暂休眠，避免出现活锁
				Thread.sleep(3, RANDOM.nextInt(500));
			}
		} catch (Exception e) {
			logger.error("Locking error:", e);
		}
		return false;
	}
	
	public boolean tryLock()  {
		try {
			if (redis.setnx(key, LOCKED, expire) == 1) {
				return true;
			}
			
			//TimeUnit.MILLISECONDS.sleep(300L);
		} catch (Exception e) {
			logger.error("Locking error:", e);
		}
		
		return false;
	}
	


	/**
	 * 加锁
	 * 应该以：
	 * lock();
	 * try {
	 * 		doSomething();
	 * } finally {
	 * 		unlock()；
	 * }
	 * 的方式调用
	 * @param timeout 超时时间
	 * @param expire 锁的超时时间（秒），过期删除
	 * @return 成功或失败标志
	 */
	public boolean lock(long timeout, int expire) {
		long nano = System.nanoTime();
		timeout *= MILLI_NANO_CONVERSION;
		try {
			
			while ((System.nanoTime() - nano) < timeout) {
				if (redis.setnx(key, LOCKED, expire) == 1) {
					return true;
				}
				// 短暂休眠，避免出现活锁
				Thread.sleep(3, RANDOM.nextInt(500));
			}
		} catch (Exception e) {
			logger.error("Locking error:", e);
		}
		return false;
	}

	/**
	 * 加锁
	 * 应该以：
	 * lock();
	 * try {
	 * 		doSomething();
	 * } finally {
	 * 		unlock()；
	 * }
	 * 的方式调用
	 * @return 成功或失败标志
	 */
	public boolean lock() {
		return lock(DEFAULT_TIME_OUT);
	}

	/**
	 * 解锁
	 * 无论是否加锁成功，都需要调用unlock
	 * 应该以：
	 * lock();
	 * try {
	 * 		doSomething();
	 * } finally {
	 * 		unlock()；
	 * }
	 * 的方式调用
	 */
	public void unlock() {

		try {
			this.redis.del(this.key);
		} catch (PiRedisExecption e) {
			throw new RuntimeException(e);
		}
	}
	
	
}

